package com.crazy.security;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.http.HttpServletRequest;
import javax.transaction.Transactional;

import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;

import com.crazy.common.constants.Const;
import com.crazy.dao.sys.PubResourceDao;
import com.crazy.entity.sys.PubResource;

/**
 * 最核心的地方，就是提供某个资源对应的权限定义，即getAttributes方法返回的结果。 <br>
 * 此类在初始化时，应该取到所有资源及其对应角色的定义。
 * 
 * @author zhang weiwei
 * @since 2013-9-6下午1:31:40
 */
@Named
public class MyFilterInvocationSecurityMetadataSource implements
		FilterInvocationSecurityMetadataSource {
	private static String MSG_KEY = "AbstractAccessDecisionManager.accessDenied";
	private static Map<String, Collection<ConfigAttribute>> resourceMap = new HashMap<String, Collection<ConfigAttribute>>();
	@Inject
	private MessageSourceAccessor accessor;
	@Inject
	private Boolean enabledSecurity;
	@Inject
	private PubResourceDao dao;

	@Override
	public Collection<ConfigAttribute> getAllConfigAttributes() {
		return new ArrayList<ConfigAttribute>();
	}

	@Override
	public Collection<ConfigAttribute> getAttributes(Object obj)
			throws IllegalArgumentException {
		if (this.enabledSecurity) {
			FilterInvocation invocation = (FilterInvocation) obj;
			HttpServletRequest request = invocation.getHttpRequest();
			for (Entry<String, Collection<ConfigAttribute>> entry : resourceMap
					.entrySet()) {
				String key = entry.getKey();
				RequestMatcher matcher = new AntPathRequestMatcher(key);
				if (matcher.matches(request)) {
					Collection<ConfigAttribute> value = entry.getValue();
					return value;
				}
			}
			String msg = this.accessor.getMessage(MSG_KEY);
			throw new AccessDeniedException(msg);
		}
		return null;
	}

	@Override
	public boolean supports(Class<?> arg0) {
		return true;
	}

	/**
	 * 获取所有资源
	 * 
	 * @author Zhang Weiwei
	 * @since 2013-9-21下午9:26:21
	 */
	@PostConstruct
	@Transactional
	public void loadResources() {
		if (this.enabledSecurity) {
			List<PubResource> list = this.dao.findByEnabled(Const.启用
					.getStatus());
			for (PubResource resource : list) {
				String name = resource.getAuthorityName();
				String url = resource.getResourceUrl();
				ConfigAttribute ca = new SecurityConfig(name);
				Collection<ConfigAttribute> value = new ArrayList<ConfigAttribute>();
				value.add(ca);
				resourceMap.put(url, value);
			}
		}
	}
}
